# 데이터 처리[[processing-the-data]]

<CourseFloatingBanner chapter={3}
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/en/chapter3/section2.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/en/chapter3/section2.ipynb"},
]} />

[이전 챕터](/course/chapter2)의 예제에 이어서, 한 배치에서 시퀀스 분류기를 훈련하는 방법은 다음과 같습니다.

```python
import torch
from torch.optim import AdamW
from transformers import AutoTokenizer, AutoModelForSequenceClassification

# 이전과 동일
checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
model = AutoModelForSequenceClassification.from_pretrained(checkpoint)
sequences = [
    "I've been waiting for a HuggingFace course my whole life.",
    "This course is amazing!",
]
batch = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt")

# 여기가 새로운 부분
batch["labels"] = torch.tensor([1, 1])

optimizer = AdamW(model.parameters())
loss = model(**batch).loss
loss.backward()
optimizer.step()
```

물론 두 문장만으로 모델을 훈련하는 것으로는 매우 좋은 결과를 얻을 수 없습니다. 더 나은 결과를 얻으려면 더 큰 데이터 세트를 준비해야 합니다.

이 섹션에서는 William B. Dolan과 Chris Brockett의 [논문](https://www.aclweb.org/anthology/I05-5002.pdf)에서 소개된 MRPC(Microsoft Research Paraphrase Corpus) 데이터 세트를 예제로 사용하겠습니다. 이 데이터 세트는 5,801개의 문장 쌍으로 구성되어 있으며, 각 쌍이 패러프레이즈인지 아닌지를 나타내는 레이블이 있습니다(즉, 두 문장이 같은 의미인지). 이 챕터에서 이 데이터 세트를 선택한 이유는 작은 데이터 세트이므로 훈련 실험을 하기에 쉽기 때문입니다.

### Hub에서 데이터 세트 가져오기[[loading-a-dataset-from-the-hub]]

<Youtube id="_BZearw7f0w"/>

Hub에는 모델뿐만 아니라 다양한 언어로 된 여러 데이터 세트도 있습니다. [여기](https://huggingface.co/datasets)에서 데이터 세트를 찾아볼 수 있으며, 이 섹션을 완료한 후에는 새로운 데이터 세트를 로드하고 처리해보는 것을 권장합니다([여기](https://huggingface.co/docs/datasets/loading)에서 일반적인 문서를 참조하세요). 하지만 지금은 MRPC 데이터 세트에 집중해보겠습니다! 이것은 [GLUE 벤치마크](https://gluebenchmark.com/)를 구성하는 10개 데이터 세트 중 하나로, 10개의 서로 다른 텍스트 분류 작업에 걸쳐 ML 모델의 성능을 측정하는 데 사용되는 학술적 벤치마크입니다.

🤗 Datasets 라이브러리는 Hub에서 데이터 세트를 다운로드하고 캐시하는 매우 간단한 명령을 제공합니다. MRPC 데이터 세트를 다음과 같이 다운로드할 수 있습니다.

> [!TIP]
> 💡 **추가 자료**: 더 많은 데이터 세트 로딩 기법과 예제를 보려면 [🤗 Datasets 문서](https://huggingface.co/docs/datasets/)를 확인하세요. 

```py
from datasets import load_dataset

raw_datasets = load_dataset("glue", "mrpc")
raw_datasets
```

```python out
DatasetDict({
    train: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 3668
    })
    validation: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 408
    })
    test: Dataset({
        features: ['sentence1', 'sentence2', 'label', 'idx'],
        num_rows: 1725
    })
})
```

보시다시피, 훈련 세트, 검증 세트, 테스트 세트가 포함된 `DatasetDict` 객체를 얻습니다. 각각은 여러 열(`sentence1`, `sentence2`, `label`, `idx`)과 가변적인 행 수를 포함하며, 이는 각 세트의 요소 수입니다(따라서 훈련 세트에는 3,668개의 문장 쌍이, 검증 세트에는 408개가, 테스트 세트에는 1,725개가 있습니다).

> [!TIP]
> 이 명령은 기본적으로 *~/.cache/huggingface/datasets*에 데이터 세트를 다운로드하고 캐시합니다. 2장에서 언급했듯이 `HF_HOME` 환경 변수를 설정하여 캐시 폴더를 맞춤 설정할 수 있습니다.

딕셔너리처럼 인덱싱하여 `raw_datasets` 객체의 각 문장 쌍에 접근할 수 있습니다.

```py
raw_train_dataset = raw_datasets["train"]
raw_train_dataset[0]
```

```python out
{'idx': 0,
 'label': 1,
 'sentence1': 'Amrozi accused his brother , whom he called " the witness " , of deliberately distorting his evidence .',
 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'}
```

레이블이 이미 정수로 되어 있으므로 여기서 전처리를 할 필요가 없습니다. 어떤 정수가 어떤 레이블에 해당하는지 알아보려면 `raw_train_dataset`의 `features`를 검사하면 됩니다. 이것은 각 열의 타입을 알려줍니다.

```py
raw_train_dataset.features
```

```python out
{'sentence1': Value(dtype='string', id=None),
 'sentence2': Value(dtype='string', id=None),
 'label': ClassLabel(num_classes=2, names=['not_equivalent', 'equivalent'], names_file=None, id=None),
 'idx': Value(dtype='int32', id=None)}
```

내부적으로 `label`은 `ClassLabel` 타입이며, 정수와 레이블 이름의 매핑이 *names* 폴더에 저장되어 있습니다. `0`은 `not_equivalent`에, `1`은 `equivalent`에 해당합니다.

> [!TIP]
> ✏️ **직접 해보기!** 훈련 세트의 15번째 요소와 검증 세트의 87번째 요소를 살펴보세요. 그들의 레이블은 무엇인가요?

### 데이터 세트 전처리[[preprocessing-a-dataset]]

<Youtube id="0u3ioSwev3s"/>

데이터 세트를 전처리하려면 텍스트를 모델이 이해할 수 있는 숫자로 변환해야 합니다. [이전 챕터](/course/chapter2)에서 보았듯이, 이는 토크나이저로 수행됩니다. 토크나이저에 한 문장이나 문장 목록을 입력할 수 있으므로, 다음과 같이 각 쌍의 모든 첫 번째 문장과 모든 두 번째 문장을 직접 토큰화할 수 있습니다.

```py
from transformers import AutoTokenizer

checkpoint = "bert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint)
tokenized_sentences_1 = tokenizer(raw_datasets["train"]["sentence1"])
tokenized_sentences_2 = tokenizer(raw_datasets["train"]["sentence2"])
```

> [!TIP]
> 💡 **심화 학습**: 더 고급 토큰화 기법과 다양한 토크나이저가 작동하는 방식을 이해하려면 [🤗 Tokenizers 문서](https://huggingface.co/docs/transformers/main/en/tokenizer_summary)와 [쿡북의 토큰화 가이드](https://huggingface.co/learn/cookbook/en/advanced_rag#tokenization-strategies)를 살펴보세요.

하지만 두 시퀀스를 모델에 전달하기만 해서는 두 문장이 패러프레이즈인지 아닌지 예측할 수 없습니다. 두 시퀀스를 쌍으로 처리하고 적절한 전처리를 적용해야 합니다. 다행히 토크나이저는 한 쌍의 시퀀스를 받아서 BERT 모델이 기대하는 방식으로 준비할 수도 있습니다.

```py
inputs = tokenizer("This is the first sentence.", "This is the second one.")
inputs
```

```python out
{ 
  'input_ids': [101, 2023, 2003, 1996, 2034, 6251, 1012, 102, 2023, 2003, 1996, 2117, 2028, 1012, 102],
  'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
  'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
}
```

[2장](/course/chapter2)에서 `input_ids`와 `attention_mask` 키에 대해 논의했지만, `token_type_ids`에 대한 이야기는 미뤄두었습니다. 이 예제에서 이것은 입력의 어느 부분이 첫 번째 문장이고 어느 부분이 두 번째 문장인지 모델에 알려주는 역할을 합니다.

> [!TIP]
> ✏️ **직접 해보기!** 훈련 세트의 15번째 요소를 가져와서 두 문장을 따로따로 토큰화하고 쌍으로도 토큰화해보세요. 두 결과의 차이점은 무엇인가요?

`input_ids` 안의 ID를 다시 단어로 디코딩하면

```py
tokenizer.convert_ids_to_tokens(inputs["input_ids"])
```

다음을 얻습니다.

```python out
['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]']
```

따라서 모델은 두 문장이 있을 때 입력이 `[CLS] sentence1 [SEP] sentence2 [SEP]` 형태이기를 기대한다는 것을 알 수 있습니다. 이를 `token_type_ids`와 맞춰보면

```python out
['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]']
[      0,      0,    0,     0,       0,          0,   0,       0,      1,    1,     1,        1,     1,   1,       1]
```

보시다시피, `[CLS] sentence1 [SEP]`에 해당하는 입력 부분은 모두 토큰 타입 ID가 `0`이고, `sentence2 [SEP]`에 해당하는 다른 부분들은 모두 토큰 타입 ID가 `1`입니다.

다른 체크포인트(checkpoint)를 선택하면 토큰화된 입력에 `token_type_ids`가 반드시 있지는 않다는 점에 주의하세요(예를 들어, DistilBERT 모델을 사용하면 반환되지 않습니다). 모델이 사전 훈련 중에 이를 본 적이 있어서 무엇을 해야 할지 알 때만 반환됩니다.

여기서 BERT는 토큰 타입 ID로 사전 훈련되었으며, [1장](/course/chapter1)에서 이야기한 마스크드 언어 모델링 목표 외에도 _다음 문장 예측_이라는 추가 목표를 가지고 있습니다. 이 작업의 목표는 문장 쌍 간의 관계를 모델링하는 것입니다.

다음 문장 예측에서는 모델에 문장 쌍(무작위로 마스킹된 토큰과 함께)이 제공되고 두 번째 문장이 첫 번째 문장을 따르는지 예측하도록 요청받습니다. 작업을 쉽지 않게 만들기 위해, 절반의 경우에는 문장들이 추출된 원본 문서에서 서로를 따르고, 나머지 절반의 경우에는 두 문장이 서로 다른 문서에서 나옵니다.

일반적으로 토큰화된 입력에 `token_type_ids`가 있는지 여부에 대해 걱정할 필요는 없습니다. 토크나이저와 모델에 동일한 체크포인트(checkpoint)를 사용하는 한, 토크나이저가 모델에 제공해야 할 것을 알고 있으므로 모든 것이 잘 될 것입니다.

이제 토크나이저가 한 쌍의 문장을 어떻게 처리할 수 있는지 보았으므로, 이를 사용하여 전체 데이터 세트를 토큰화할 수 있습니다: [이전 챕터](/course/chapter2)에서처럼, 첫 번째 문장 목록과 두 번째 문장 목록을 제공하여 토크나이저에 문장 쌍 목록을 입력할 수 있습니다. 이는 [2장](/course/chapter2)에서 본 패딩과 생략 옵션과도 호환됩니다. 따라서 훈련 데이터 세트를 전처리하는 한 가지 방법은

```py
tokenized_dataset = tokenizer(
    raw_datasets["train"]["sentence1"],
    raw_datasets["train"]["sentence2"],
    padding=True,
    truncation=True,
)
```

이것은 잘 작동하지만, 딕셔너리(키는 `input_ids`, `attention_mask`, `token_type_ids`이고 값은 목록의 목록)를 반환한다는 단점이 있습니다. 또한 토큰화 중에 전체 데이터 세트를 메모리에 저장할 수 있는 충분한 RAM이 있는 경우에만 작동합니다(🤗 Datasets 라이브러리의 데이터 세트는 디스크에 저장된 [Apache Arrow](https://arrow.apache.org/) 파일이므로, 요청한 샘플만 메모리에 로드됩니다).

데이터를 데이터 세트로 유지하려면 [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) 메소드를 사용하겠습니다. 이는 토큰화 이상의 전처리가 필요한 경우 추가적인 유연성도 제공합니다. `map()` 메소드는 데이터 세트의 각 요소에 함수를 적용하여 작동하므로, 입력을 토큰화하는 함수를 정의해보겠습니다.

```py
def tokenize_function(example):
    return tokenizer(example["sentence1"], example["sentence2"], truncation=True)
```

이 함수는 딕셔너리(데이터 세트의 항목과 같은)를 받아서 `input_ids`, `attention_mask`, `token_type_ids` 키가 있는 새 딕셔너리를 반환합니다. `example` 딕셔너리에 여러 샘플이 포함되어 있어도(각 키가 문장 목록으로) 작동한다는 점에 주목하세요. 앞서 본 것처럼 `tokenizer`는 문장 쌍의 목록에서 작동하기 때문입니다. 이를 통해 `map()` 호출에서 `batched=True` 옵션을 사용할 수 있으며, 이는 토큰화를 크게 가속화할 것입니다. `tokenizer`는 [🤗 Tokenizers](https://github.com/huggingface/tokenizers) 라이브러리의 Rust로 작성된 토크나이저로 뒷받침됩니다. 이 토크나이저는 매우 빠를 수 있지만, 한 번에 많은 입력을 제공해야만 그렇습니다.

지금은 토큰화 함수에서 `padding` 인수를 빼둔 것에 주목하세요. 모든 샘플을 최대 길이로 패딩하는 것은 효율적이지 않기 때문입니다. 배치를 만들 때 샘플을 패딩하는 것이 더 좋습니다. 그러면 해당 배치의 최대 길이까지만 패딩하면 되고, 전체 데이터 세트의 최대 길이까지 패딩할 필요가 없기 때문입니다. 입력의 길이가 매우 다양할 때 많은 시간과 처리 능력을 절약할 수 있습니다!

> [!TIP]
> 📚 **성능 팁**: 효율적인 데이터 처리 기법에 대한 자세한 내용은 [🤗 Datasets 성능 가이드](https://huggingface.co/docs/datasets/about_arrow)에서 배울 수 있습니다.

다음은 모든 데이터 세트에 토큰화 함수를 한 번에 적용하는 방법입니다. `map` 호출에서 `batched=True`를 사용하므로 함수가 데이터 세트의 각 요소에 개별적으로가 아니라 여러 요소에 한 번에 적용됩니다. 이를 통해 더 빠른 전처리가 가능합니다.

```py
tokenized_datasets = raw_datasets.map(tokenize_function, batched=True)
tokenized_datasets
```

🤗 Datasets 라이브러리가 이 처리를 적용하는 방식은 전처리 함수가 반환하는 딕셔너리의 각 키에 대해 데이터 세트에 새 필드를 추가하는 것입니다.

```python out
DatasetDict({
    train: Dataset({
        features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'],
        num_rows: 3668
    })
    validation: Dataset({
        features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'],
        num_rows: 408
    })
    test: Dataset({
        features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'],
        num_rows: 1725
    })
})
```

`num_proc` 인수를 전달하여 `map()`으로 전처리 함수를 적용할 때 멀티프로세싱을 사용할 수도 있습니다. 🤗 Tokenizers 라이브러리가 이미 여러 스레드를 사용하여 샘플을 더 빠르게 토큰화하므로 여기서는 이를 사용하지 않았지만, 이 라이브러리가 뒷받침하는 빠른 토크나이저를 사용하지 않는다면 전처리 속도를 높일 수 있습니다.

우리의 `tokenize_function`은 `input_ids`, `attention_mask`, `token_type_ids` 키가 있는 딕셔너리를 반환하므로, 이 세 필드가 데이터 세트의 모든 분할에 추가됩니다. 전처리 함수가 `map()`을 적용한 데이터 세트의 기존 키에 대한 새 값을 반환한다면 기존 필드를 변경할 수도 있었을 것입니다.

마지막으로 해야 할 일은 요소들을 배치로 묶을 때 모든 예제를 가장 긴 요소의 길이로 패딩하는 것입니다 — 이 기법을 *동적 패딩*이라고 합니다.

##### 동적 패딩[[dynamic-padding]]

<Youtube id="7q5NyFT8REg"/>

배치 내에서 샘플들을 함께 배치하는 역할을 하는 함수를 *collate function*이라고 합니다. 이는 `DataLoader`를 구축할 때 전달할 수 있는 인수로, 기본값은 샘플을 PyTorch 텐서로 변환하고 연결하는 함수입니다(요소가 목록, 튜플 또는 딕셔너리인 경우 재귀적으로). 우리의 경우 입력이 모두 같은 크기가 아니므로 이것은 불가능할 것입니다. 우리는 의도적으로 패딩을 연기하여 각 배치에서만 필요에 따라 적용하고 많은 패딩이 있는 지나치게 긴 입력을 피했습니다. 이것은 훈련을 상당히 가속화할 것이지만, TPU에서 훈련하는 경우 문제를 일으킬 수 있다는 점에 주의하세요 — TPU는 추가 패딩이 필요하더라도 고정된 모양을 선호합니다.

> [!TIP]
> 🚀 **최적화 가이드**: 패딩 전략과 TPU 고려사항을 포함한 훈련 성능 최적화에 대한 자세한 내용은 [🤗 Transformers 성능 문서](https://huggingface.co/docs/transformers/main/en/performance)를 참조하세요.

실제로 이를 수행하려면 함께 배치하려는 데이터 세트 항목에 적절한 양의 패딩을 적용할 collate function을 정의해야 합니다. 다행히 🤗 Transformers 라이브러리는 `DataCollatorWithPadding`을 통해 이러한 함수를 제공합니다. 인스턴스화할 때 토크나이저를 받아서(어떤 패딩 토큰을 사용할지, 모델이 입력의 왼쪽 또는 오른쪽에 패딩을 기대하는지 알기 위해) 필요한 모든 것을 수행합니다.

```py
from transformers import DataCollatorWithPadding

data_collator = DataCollatorWithPadding(tokenizer=tokenizer)
```

이 새로운 도구를 테스트하기 위해, 함께 배치하고 싶은 훈련 세트에서 몇 개의 샘플을 가져와보겠습니다. 여기서는 `idx`, `sentence1`, `sentence2` 열을 제거합니다. 이들은 필요하지 않고 문자열을 포함하고 있으며(문자열로는 텐서를 만들 수 없음), 배치의 각 항목 길이를 살펴보겠습니다.

```py
samples = tokenized_datasets["train"][:8]
samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "sentence2"]}
[len(x) for x in samples["input_ids"]]
```

```python out
[50, 59, 47, 67, 59, 50, 62, 32]
```

당연히 32부터 67까지 다양한 길이의 샘플을 얻습니다. 동적 패딩은 이 배치의 샘플들이 모두 배치 내 최대 길이인 67로 패딩되어야 함을 의미합니다. 동적 패딩이 없다면, 모든 샘플이 전체 데이터 세트의 최대 길이나 모델이 받을 수 있는 최대 길이로 패딩되어야 할 것입니다. `data_collator`가 배치를 동적으로 올바르게 패딩하는지 다시 확인해보겠습니다.

```py
batch = data_collator(samples)
{k: v.shape for k, v in batch.items()}
```

```python out
{'attention_mask': torch.Size([8, 67]),
 'input_ids': torch.Size([8, 67]),
 'token_type_ids': torch.Size([8, 67]),
 'labels': torch.Size([8])}
```

좋아 보입니다! 이제 원시 텍스트에서 모델이 처리할 수 있는 배치까지 만들었으므로, 미세 조정할 준비가 되었습니다!

> [!TIP]
> ✏️ **직접 해보기!** GLUE SST-2 데이터 세트에서 전처리를 복제해보세요. 쌍이 아닌 단일 문장으로 구성되어 있어 약간 다르지만, 나머지는 동일하게 보일 것입니다. 더 어려운 도전을 위해서는 GLUE 작업 중 어떤 것에서도 작동하는 전처리 함수를 작성해보세요.
>
> 📖 **추가 연습**: [🤗 Transformers 예제](https://huggingface.co/docs/transformers/main/en/notebooks)에서 이러한 실습 예제들을 확인해보세요.

완벽합니다! 이제 🤗 Datasets 라이브러리의 최신 모범 사례로 데이터를 전처리했으므로, 최신 Trainer API를 사용하여 모델을 훈련할 준비가 되었습니다. 다음 섹션에서는 Hugging Face 생태계에서 사용할 수 있는 최신 기능과 최적화를 사용하여 모델을 효과적으로 미세 조정하는 방법을 보여드리겠습니다.

## 섹션 퀴즈[[section-quiz]]

데이터 처리 개념에 대한 이해도를 테스트해보세요.

### 1. `batched=True`와 함께 `Dataset.map()`을 사용하는 주요 장점은 무엇인가요?

<Question
	choices={[
		{
			text: "메모리를 덜 사용합니다.",
			explain: "더 메모리 효율적일 수 있지만, 이것이 주요 장점은 아닙니다."
		},
		{
			text: "여러 예제를 한 번에 처리하여 토큰화를 훨씬 빠르게 만듭니다.",
			explain: "정답입니다! 배치로 처리하면 빠른 토크나이저가 여러 예제를 동시에 작업할 수 있어 속도가 크게 향상됩니다.",
            correct: true
		},
		{
			text: "자동으로 패딩을 처리해줍니다.",
			explain: "배치 처리가 자동으로 패딩을 처리하지는 않습니다 - 그것은 데이터 콜레이터가 수행합니다."
		},
        {
			text: "데이터를 PyTorch 텐서로 변환합니다.",
			explain: "텐서 변환은 형식을 설정할 때 발생하며, 배치 매핑 중에는 발생하지 않습니다."
		}
	]}
/>

### 2. 데이터 세트의 최대 길이로 모든 시퀀스를 패딩하는 대신 동적 패딩을 사용하는 이유는 무엇인가요?

<Question
	choices={[
		{
			text: "동적 패딩이 모델 아키텍처에 의해 요구됩니다.",
			explain: "아니요, 모델은 고정 패딩과 동적 패딩을 모두 처리할 수 있습니다."
		},
		{
			text: "각 배치의 최대 길이까지만 패딩하여 계산 오버헤드를 줄입니다.",
			explain: "정답입니다! 동적 패딩은 데이터 세트 최대값이 아닌 배치 최대값까지만 패딩하여 패딩 토큰에 대한 불필요한 계산을 피합니다.",
            correct: true
		},
		{
			text: "모델 정확도를 향상시킵니다.",
			explain: "패딩 전략은 모델 정확도에 직접적인 영향을 주지 않습니다."
		},
        {
			text: "DataCollatorWithPadding을 사용할 때 필수입니다.",
			explain: "DataCollatorWithPadding이 동적 패딩을 가능하게 하지만, 원한다면 여전히 고정 패딩을 사용할 수 있습니다."
		}
	]}
/>

### 3. BERT 토큰화에서 `token_type_ids` 필드는 무엇을 나타내나요?

<Question
	choices={[
		{
			text: "시퀀스에서 각 토큰의 위치입니다.",
			explain: "그것은 위치 임베딩이지, token_type_ids가 아닙니다."
		},
		{
			text: "문장 쌍을 처리할 때 각 토큰이 어느 문장에 속하는지를 나타냅니다.",
			explain: "정답입니다! token_type_ids는 문장 쌍 작업에서 첫 번째 문장(0)과 두 번째 문장(1)을 구분합니다.",
            correct: true
		},
		{
			text: "각 토큰의 어텐션 마스크입니다.",
			explain: "어텐션 마스크는 어떤 토큰에 주의를 기울일지 나타내는 별도의 필드입니다."
		},
        {
			text: "각 토큰의 어휘 ID입니다.",
			explain: "그것은 token_type_ids가 아닌 input_ids 필드입니다."
		}
	]}
/>

### 4. `load_dataset('glue', 'mrpc')`로 데이터 세트를 로딩할 때 두 번째 인수는 무엇을 지정하나요?

<Question
	choices={[
		{
			text: "로딩할 데이터 세트의 버전입니다.",
			explain: "버전 지정은 다른 매개변수를 사용합니다."
		},
		{
			text: "GLUE 벤치마크 내의 특정 작업 또는 하위 집합입니다.",
			explain: "정답입니다! MRPC는 더 큰 GLUE 벤치마크 컬렉션 내의 특정 작업 중 하나입니다.",
            correct: true
		},
		{
			text: "데이터 세트의 분할(train/validation/test)입니다.",
			explain: "분할은 로딩 후에 접근하며, load_dataset 호출에서 지정하지 않습니다."
		},
        {
			text: "데이터를 반환할 형식입니다.",
			explain: "형식은 로딩 후 set_format() 메소드를 사용하여 설정합니다."
		}
	]}
/>

### 5. 훈련 전에 'sentence1'과 'sentence2' 같은 열을 제거하는 목적은 무엇인가요?

<Question
	choices={[
		{
			text: "훈련 중 메모리를 절약하기 위해서입니다.",
			explain: "약간의 메모리는 절약되지만, 이것이 주된 이유는 아닙니다."
		},
		{
			text: "모델이 이러한 원시 텍스트 열을 예상하지 않고 오류가 발생할 수 있기 때문입니다.",
			explain: "정답입니다! 모델은 원시 텍스트 문자열이 아닌 수치적 텐서를 예상합니다. 텍스트 열을 유지하면 오류가 발생할 것입니다.",
            correct: true
		},
		{
			text: "이러한 열들이 평가에 필요하지 않기 때문입니다.",
			explain: "사실이긴 하지만, 주된 이유는 모델이 원시 텍스트를 처리할 수 없다는 것입니다."
		},
        {
			text: "훈련 속도를 크게 향상시키기 때문입니다.",
			explain: "호환되지 않는 데이터 타입으로 인한 오류 방지에 비해 속도 향상은 미미합니다."
		}
	]}
/>

> [!TIP]
> 💡 **핵심 요점**
> - 전처리를 훨씬 빠르게 하려면 `Dataset.map()`에서 `batched=True`를 사용하세요
> - `DataCollatorWithPadding`을 사용한 동적 패딩이 고정 길이 패딩보다 효율적입니다
> - 모델의 추론 결과물(수치적 텐서, 올바른 열 이름)에 맞게 항상 데이터를 전처리하세요
> - 🤗 Datasets 라이브러리는 대규모 효율적인 데이터 처리를 위한 강력한 도구를 제공합니다